﻿#include "VectorType.h"

#include "GenericInfo.h"
#include "Containers/ReflectableVector.h"

#include "NativeFunction.h"
#include "FunctionList.h"
#include "GarbageCollectable.h"

CString CTVectorType::PlaceholderName = U"T";

CTVectorType::CTVectorType()
    :CType(
        STypeID(CType::GetEngineCoreNamespace()+U"::TNativeVector",true)
        ,ETypeFlags::Generic | ETypeFlags::Vector
    )
{

    GenericInfo=new CGenericInfo();

    CPlaceholderType* VectorPlaceholderType = 
        new CPlaceholderType(
            STypeID(GetFullName()+U"::"+PlaceholderName,true)
            ,ETypeFlags::None
            ,0
            ,this);
    GenericInfo->PlaceholderTypes.Add(VectorPlaceholderType);

    //add functions
    Functions=new CFunctionList(this);
    {
        //add function  
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"Add"
            , CGetType<void>()()
            , {VectorPlaceholderType}
            ,{}
            );
    }

    {
        //Num function
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"Num"
            , CGetType<uint64_t>()()
            ,{}
            ,{});

    }

    CNativeFunction* AtFunction=nullptr;
    {
        //At function
        CNativeFunction* NativeFunction = new CNativeFunction(
                Functions
                ,U"At"
                , VectorPlaceholderType
                ,{CGetType<uint64_t>()()}
                ,{});



        AtFunction=NativeFunction;
    }

    CNativeFunction* SetAtFunction=nullptr;
    {
        //SetAt function
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"SetAt"
            , CGetType<void>()()
            ,{CGetType<uint64_t>()(),VectorPlaceholderType}
            ,{});

        SetAtFunction=NativeFunction;
    }
    

    {
        //create a indexer in functions
        CFunctionList::SIndexer Indexer;
        Indexer.Getter=AtFunction;
        Indexer.Setter=SetAtFunction;
        Indexer.ParameterTypes.Add(CGetType<uint64_t>()() /* vector index type*/  );
    
        Functions->Indexers.Add(Indexer);
    }

    //add clear function
    {
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"Clear"
            , CGetType<void>()()
            ,{}
            ,{});

    }

    //add Reserve function
    {
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"Reserve"
            , CGetType<void>()()
            ,{CGetType<int64_t>()()}
            ,{});

    }

    //add Resize function
    {
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"Resize"
            , CGetType<void>()()
            ,{CGetType<int64_t>()()}
            ,{});

    }

}

CTVectorType *CTVectorType::GetStaticType()
{
    static CTVectorType* StaticType = new CTVectorType();
    return StaticType;
}


CString CTVectorType::CreateTypeName(const CString &ElementType)
{
    return STypeID::CreateTemplateTypeName(
        GetStaticType()->GetFullName()
        ,{ElementType}
        ,{PlaceholderName}
        );
}

STypeID CTVectorType::CreateID(const SDecoratedType &ElementType)
{
    return STypeID(
        GetStaticType()->ID
        ,{ElementType.BasicType->ID}
        ,{PlaceholderName}
        );
}

static uint8_t RegisterTypesCaller=(CTVectorType::GetStaticType(),0);

class CVectorInstance : public ITypeInstance
{
protected:
    CTVectorGeneralized* Type;
public:
    CVectorInstance(CTVectorGeneralized* InType)
        :Type(InType)
    {
    }

    virtual uint32_t GetSize() override
    {
        return sizeof(CReflectableVector);
    }

    virtual void InitInstance(void *Memory)
    {
        new (Memory) CReflectableVector();
    }

    virtual void CloneInstance(const void *Instance, void *Memory)
    {
        new (Memory) CReflectableVector(Type->GetElementType().BasicType,*(CReflectableVector*)Instance);
    }

    virtual void EraseInstance(void *InValue)
    {
        reinterpret_cast<CReflectableVector*>(InValue)->Clear(Type->GeneralizedInfo->TypeArguments[0],false);
        reinterpret_cast<CReflectableVector*>(InValue)->~CReflectableVector();
    }

    virtual uint64_t GetInstanceHash(const void *InInstance) const override
    {
        return reinterpret_cast<CReflectableVector const*>(InInstance)->GetHashCode(Type->GetElementType().BasicType);
    }

    virtual bool IsInstanceEqual(const void *A,const void *B) const override
    {
        return reinterpret_cast<CReflectableVector const*>(A)->IsEqual(Type->GetElementType().BasicType,*reinterpret_cast<CReflectableVector const*>(B));
    }

    virtual void *CreateInstance() override
    {
        return new CReflectableVector();
    }

    virtual void ResetAllocated(void *Memory) override
    {
        reinterpret_cast<CReflectableVector*>(Memory)->Clear(Type->GetElementType().BasicType,true);
    }

    virtual CString ToDebugString(const void *InInstance) const override
    {
        return Type->GetFullName();
    }

    virtual int64_t GetDebugNamedChildNum(const void * Instance) const override
    { 
        return 2; //size and capacity
    }

    virtual CString GetDebugNamedChildName(int64_t Index,const void * Instance) const override
    { 
        switch(Index)
        {
            case 0:
                return U"大小(Num)";
            case 1:
                return U"容量(Capacity)";
            default:
                assert(false && "index out of range");
                return U"";
        }
    }

    virtual CType* GetDebugNamedChildType(int64_t Index,const void * Instance) const override
    { 
        return CGetType<uint64_t>()();
    }
    
    virtual const void* GetDebugNamedChildValue(int64_t Index,const void * Instance) const override
    { 
        switch(Index)
        {
            case 0:
                return reinterpret_cast<CReflectableVector const*>(Instance)->NumPtr();
            case 1:
                return reinterpret_cast<CReflectableVector const*>(Instance)->CapacityPtr();
            default:
                assert(false && "index out of range");
                return nullptr;
        }
    }

    virtual int64_t GetDebugIndexedChildNum(const void * Instance) const override
    {
        return reinterpret_cast<CReflectableVector const*>(Instance)->Num(); 
    } 

    virtual CType* GetDebugIndexedChildType(int64_t Index,const void * Instance) const override
    { 
        return Type->GetElementType().BasicType;
    } 

    virtual const void* GetDebugIndexedChildValue(int64_t Index,const void * Instance) const 
    { 
        return reinterpret_cast<CReflectableVector const*>(Instance)->At(Type->GetElementType().BasicType,Index);
    }

};

class CVectorGC : public IGarbageCollectable
{
protected:
    CTVectorGeneralized* Type;
public:
    CVectorGC(CTVectorGeneralized* InType)
        :Type(InType)
    {
    }

    virtual void CollectReferencedObjects(
        void* InInstance,
        TForwardForwardLinkedList<RObject*>& OutReferencedObjects
    ) override
    {
        CReflectableVector* Vector=reinterpret_cast<CReflectableVector*>(InInstance);
        auto ElementType = Type->GetElementType().BasicType;
        for(uint32_t i=0;i<Vector->Num();++i)
        {
            ElementType->GarbageCollectable->CollectReferencedObjects(Vector->At(Type->GetElementType().BasicType,i),OutReferencedObjects);
        }
    }
};

CTVectorGeneralized::CTVectorGeneralized( const SDecoratedType&  InElementType)
    :CType(
      CTVectorType::CreateID(InElementType)  
      ,ETypeFlags::Vector | ETypeFlags::Generalized
      |(InElementType.BasicType->IsScriptType()?ETypeFlags::Script : ETypeFlags::None)
      | (InElementType.BasicType->CanUseInScript()? ETypeFlags::None : ETypeFlags::CantUseInScript)
    )
{
    Instancable=new CVectorInstance(this);
    if(InElementType.BasicType->GarbageCollectable)
    {
        GarbageCollectable=new CVectorGC(this);
    }

    GeneralizedInfo=new CGeneralizedInfo();
    GeneralizedInfo->TemplateType=CTVectorType::GetStaticType();
    GeneralizedInfo->TypeArguments.Add(InElementType.BasicType);

    GeneralizedInfo->TemplateType->GenericInfo->GeneralizedTypes.Add(this);
    reinterpret_cast<CGenericInfo*>(GeneralizedInfo->TemplateType->GenericInfo)
        ->GenericMap.Add(TVector<CType*>({InElementType.BasicType}),this);

    //add functions
    Functions=new CFunctionList(this);
    {
        //add function  
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"Add"
            , CGetType<void>()()
            , {InElementType}
            ,{}
            );
        
        //NativeFunction->AddParameter(InElementType);
        NativeFunction->SetCppBody([InElementType](const TVector<CAny>& InArgs)->CAny
        {
            CReflectableVector* Vector=*reinterpret_cast<CReflectableVector**>(InArgs[0].GetPointer());
            Vector->Add(InElementType.BasicType,InArgs[1].GetPointer());
            return CAny();
        });
    }

    {
        //Num function
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"Num"
            , CGetType<uint64_t>()()
            , {}
            ,{}
            );
        
        NativeFunction->SetCppBody([](const TVector<CAny>& InArgs)->CAny
        {
            CReflectableVector* Vector=*reinterpret_cast<CReflectableVector**>(InArgs[0].GetPointer());
            return Vector->Num();
        });

    }

    CNativeFunction* AtFunction=nullptr;
    {
        //At function
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"At"
            , InElementType
            , {CGetType<uint64_t>()()}
            ,{}
            );

        //NativeFunction->AddParameter(CGetType<uint64_t>()());

        NativeFunction->SetCppBody([InElementType](const TVector<CAny>& InArgs)->CAny
        {
            CReflectableVector* Vector=*reinterpret_cast<CReflectableVector**>(InArgs[0].GetPointer());
            uint64_t Index=AnyCast<uint64_t>(InArgs[1]);
            assert(Index<Vector->Num() && "index out of range");
            auto ValuePtr=Vector->At(InElementType.BasicType,Index);
            return CAny(InElementType.BasicType
                ,InElementType.BasicType->CloneInstance(ValuePtr)
                );
        });

        AtFunction=NativeFunction;
    }

    CNativeFunction* SetAtFunction=nullptr;
    {
        //SetAt function
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"SetAt"
            , CGetType<void>()()
            , {CGetType<uint64_t>()(),InElementType}
            ,{}
            );

        // NativeFunction->AddParameter(CGetType<uint64_t>()());
        // NativeFunction->AddParameter(InElementType);

        NativeFunction->SetCppBody([InElementType](const TVector<CAny>& InArgs)->CAny
        {
            CReflectableVector* Vector=*reinterpret_cast<CReflectableVector**>(InArgs[0].GetPointer());
            Vector->SetAt(InElementType.BasicType,AnyCast<uint64_t>(InArgs[1]),InArgs[2].GetPointer());
            return CAny();
        });

        SetAtFunction=NativeFunction;
    }

    {
        //create a indexer in functions
        CFunctionList::SIndexer Indexer;
        Indexer.Getter=AtFunction;
        Indexer.Setter=SetAtFunction;
        Indexer.ParameterTypes.Add(CGetType<uint64_t>()() /* vector index type*/  );
    
        Functions->Indexers.Add(Indexer);
    }

    //add clear function
    {
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"Clear"
            , CGetType<void>()()
            ,{}
            ,{});

        NativeFunction->SetCppBody([InElementType](const TVector<CAny>& InArgs)->CAny
        {
            CReflectableVector* Vector=*reinterpret_cast<CReflectableVector**>(InArgs[0].GetPointer());
            Vector->Clear(InElementType.BasicType,true);
            return CAny();
        });

    }

    //add Reserve function
    {
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"Reserve"
            , CGetType<void>()()
            ,{CGetType<int64_t>()()}
            ,{});

        NativeFunction->SetCppBody([InElementType](const TVector<CAny>& InArgs)->CAny
        {
            CReflectableVector* Vector=*reinterpret_cast<CReflectableVector**>(InArgs[0].GetPointer());
            Vector->Reserve(InElementType.BasicType,AnyCast<int64_t>(InArgs[1]));
            return CAny();
        });

    }

    //add Resize function
    {
        CNativeFunction* NativeFunction = new CNativeFunction(
            Functions
            ,U"Resize"
            , CGetType<void>()()
            ,{CGetType<int64_t>()()}
            ,{});

        NativeFunction->SetCppBody([InElementType](const TVector<CAny>& InArgs)->CAny
        {
            CReflectableVector* Vector=*reinterpret_cast<CReflectableVector**>(InArgs[0].GetPointer());
            Vector->Resize(InElementType.BasicType,AnyCast<int64_t>(InArgs[1]));
            return CAny();
        });

    }

}

SDecoratedType CTVectorGeneralized::GetElementType() const
{
    return GeneralizedInfo->TypeArguments[0];
}

uint32_t CTVectorGeneralized::GetVectorNum(const void *InValue)
{
    return reinterpret_cast<const CReflectableVector*>(InValue)->Num();
}

void *CTVectorGeneralized::GetVectorItem(const void *InValue, uint32_t Index)
{
    return reinterpret_cast<const CReflectableVector*>(InValue)->At(GeneralizedInfo->TypeArguments[0],Index);
}
